﻿using System.Collections;
using System.Text;

namespace System.NETool;

/// <summary>
/// CRC32校验类
/// </summary>
public class Crc32
{
    private readonly uint _poly;
    private uint[] _tab;

    /// <summary>
    /// 构造函数
    /// </summary>
    public Crc32() : this(79764919U) { }

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="poly">poly</param>
    public Crc32(uint poly) { _poly = poly; }

    private void Init()
    {
        if (_tab != null)
        {
            return;
        }

        _tab = new uint[256];
        for (uint index1 = 0U; index1 < 256U; ++index1)
        {
            uint num = index1;
            for (int index2 = 0; index2 < 8; ++index2)
            {
                if (((int)num & 1) == 0)
                {
                    num >>= 1;
                }
                else
                {
                    num = num >> 1 ^ _poly;
                }
            }

            _tab[(int)index1] = num;
        }
    }

    /// <summary>
    /// 计算哈希值
    /// </summary>
    /// <param name="text">文本</param>
    /// <returns>结果</returns>
    public uint ComputeHash(string text)
    {
        return ComputeHash(Encoding.UTF8.GetBytes(text));
    }

    /// <summary>
    /// 计算哈希值
    /// </summary>
    /// <param name="data">数组</param>
    /// <returns>哈希值</returns>
    public uint ComputeHash(byte[] data)
    {
        return ComputeHash(data, 0, data.Length);
    }

    /// <summary>
    /// 计算哈希值
    /// </summary>
    /// <param name="data">数据</param>
    /// <param name="start">起始位置</param>
    /// <param name="length">长度</param>
    /// <returns>哈希值</returns>
    public uint ComputeHash(byte[] data, int start, int length)
    {
        return ComputeHash<byte[]>(data, start, length);
    }

    /// <summary>
    /// 计算哈希值
    /// </summary>
    /// <param name="data">数据</param>
    /// <param name="start">起始位置</param>
    /// <param name="length">长度</param>
    /// <typeparam name="T">类型</typeparam>
    /// <returns>哈希值</returns>
    public uint ComputeHash<T>(T data, int start, int length) where T : IList
    {
        Init();
        uint num1 = uint.MaxValue;
        for (int index = 0; index < length; ++index)
        {
            byte num2 = (byte)data[index + start];
            num1 = num1 << 8 ^ _tab[num2 ^ num1 >> 24];
        }

        return ~num1;
    }
}

/// <summary>
/// Adler32校验类
/// </summary>
internal class Adler32
{
    private static uint _checksum = 1;

    /// <summary>Performs the hash algorithm on given data array.</summary>
    /// <param name="array">Input data.</param>
    /// <param name="start">The position to begin reading from.</param>
    /// <param name="length">How many bytes in the array to read.</param>
    public static uint ComputeHash(byte[] array, int start, int length)
    {
        var s1 = _checksum & 0xFFFF;
        var s2 = _checksum >> 16;

        while (length > 0)
        {
            var n = (3800 > length) ? length : 3800;
            length -= n;
            while (--n >= 0)
            {
                s1 = s1 + (uint)(array[start++] & 0xFF);
                s2 = s2 + s1;
            }

            s1 %= 65521;
            s2 %= 65521;
        }

        _checksum = (s2 << 16) | s1;
        return _checksum;
    }
}